// ServerMain.java 最终版本
package com.nosql.db;

import com.nosql.db.cluster.ClusterManager;
import com.nosql.db.cluster.Node;
import com.nosql.db.core.storage.LSMStore;
import com.nosql.db.network.DBServer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class Servermain {
    private static final Logger logger = LogManager.getLogger(Servermain.class);

    public static void main(String[] args) {
        try {
            // 1. 加载基础配置确定节点ID
            String nodeId = System.getProperty("node.id");
            if (nodeId == null) {
                throw new IllegalArgumentException("base.properties必须包含node.id配置");
            }

            // 2. 加载节点专属配置
            System.out.println("[启动] 节点ID: " + nodeId);

            Properties nodeConfig = loadNodeConfig(nodeId);
            System.out.println("[配置] 加载配置: " + nodeConfig);

            // 打印关键配置
            System.out.printf("[配置] 角色: %s, 端口: %s, 数据目录: %s%n",
                    nodeConfig.getProperty("node.role"),
                    nodeConfig.getProperty("server.port"),
                    nodeConfig.getProperty("data.dir"));
            validateNodeConfig(nodeConfig);

            
            
            // 3. 初始化存储引擎
            Path dataDir = Paths.get(nodeConfig.getProperty("data.dir"));
            int maxMemTableSize = Integer.parseInt(nodeConfig.getProperty("max.memtable.size"));
            LSMStore store = new LSMStore(dataDir, maxMemTableSize);

            // 4. 初始化集群管理器
            ClusterManager cluster = new ClusterManager(
                    nodeId,
                    nodeConfig.getProperty("node.role"),
                    nodeConfig,
                    store
            );
            // 将节点检查移动到cluster初始化之后
            if ("FOLLOWER".equals(nodeConfig.getProperty("node.role"))) {
                // 使用ClusterManager实例调用parseNodes
                List<Node> seedNodes = cluster.parseNodes(nodeConfig.getProperty("cluster.seeds"));
                checkSeedNodesReachable(seedNodes);
            }
            // 5. 启动网络服务
            int port = Integer.parseInt(nodeConfig.getProperty("server.port"));
            new DBServer(port, store, cluster).start();

        } catch (Exception e) {
            logger.error("Server startup failed: {}", e.getMessage(), e);
        }
    }
    // 新增网络检查方法
    private static void checkSeedNodesReachable(List<Node> seedNodes) throws IOException {
        for (Node node : seedNodes) {
            try (Socket socket = new Socket()) {
                socket.connect(new InetSocketAddress(node.getHost(), node.getPort()), 3000);
                System.out.println("种子节点可达: " + node.getHost() + ":" + node.getPort());
            } catch (IOException e) {
                throw new IOException("种子节点不可达: " + node.getHost() + ":" + node.getPort(), e);
            }
        }
    }
    private static Properties loadBaseConfig() throws IOException {
        Path baseConfigPath = Paths.get("config/base.properties");
        if (!Files.exists(baseConfigPath)) {
            throw new FileNotFoundException("基础配置文件缺失: config/base.properties");
        }

        Properties config = new Properties();
        try (InputStream input = Files.newInputStream(baseConfigPath)) {
            config.load(input);
        }
        return config;
    }

    private static Properties loadNodeConfig(String nodeId) throws IOException {
        Path nodeConfigPath = Paths.get("config/" + nodeId + ".properties");
        if (!Files.exists(nodeConfigPath)) {
            throw new FileNotFoundException("节点配置文件缺失: " + nodeConfigPath);
        }

        Properties config = new Properties();
        try (InputStream input = Files.newInputStream(nodeConfigPath)) {
            config.load(input);
        }
        return config;
    }

    private static void validateNodeConfig(Properties config) {
        String[] requiredKeys = {
                "node.role",
                "server.port",
                "data.dir",
                "max.memtable.size"
        };

        for (String key : requiredKeys) {
            if (!config.containsKey(key)) {
                throw new IllegalArgumentException("节点配置缺失必要参数: " + key);
            }
        }

        // 角色相关校验
        String role = config.getProperty("node.role");
        if ("LEADER".equals(role) && !config.containsKey("cluster.nodes")) {
            throw new IllegalArgumentException("Leader节点必须配置cluster.nodes");
        }
        if ("FOLLOWER".equals(role) && !config.containsKey("cluster.seeds")) {
            throw new IllegalArgumentException("Follower节点必须配置cluster.seeds");
        }
    }
}

